package gpsparser

import (
	"strings"
	"time"

	"github.com/project-flogo/core/activity"
	"github.com/project-flogo/core/data/metadata"

	nmea "github.com/masterclock/go-nmea"
)

func init() {
	_ = activity.Register(&Activity{}, New) //activity.Register(&Activity{}, New) to create instances using factory method 'New'
}

var activityMd = activity.ToMetadata(&Settings{}, &Input{}, &Output{})

//New optional factory method, should be used if one activity instance per configuration is desired
func New(ctx activity.InitContext) (activity.Activity, error) {

	s := &Settings{}
	err := metadata.MapToStruct(ctx.Settings(), s, true)
	if err != nil {
		return nil, err
	}

	// ctx.Logger().Debugf("Setting: %s", s.ASetting)

	act := &Activity{} //add aSetting to instance

	return act, nil
}

// Activity is an sample Activity that can be used as a base to create a custom activity
type Activity struct {
}

// Metadata returns the activity's metadata
func (a *Activity) Metadata() *activity.Metadata {
	return activityMd
}

// Eval implements api.Activity.Eval - Logs the Message
func (a *Activity) Eval(ctx activity.Context) (done bool, err error) {

	input := &Input{}
	err = ctx.GetInputObject(input)
	if err != nil {
		return true, err
	}

	s, err := nmea.Parse(strings.TrimSpace(input.Sentence))
	if err != nil {
		return true, err
	}
	hasData := false
	data := map[string]interface{}{}
	switch s.DataType() {
	case nmea.TypeRMC:
		{
			m := s.(nmea.RMC)
			data["validity"] = m.Validity
			data["latitude"] = m.Latitude
			data["longitude"] = m.Longitude
			data["speed"] = m.Speed
			data["course"] = m.Course
			data["timestamp"] = toTimestamp(m.Date, m.Time)
			data["variation"] = m.Variation
			hasData = true
		}
	default:
		{
			ctx.Logger().Errorf("unsupported sentence: %s", input.Sentence)
		}
	}

	if hasData {
		output := &Output{
			Data: data,
		}
		err = ctx.SetOutputObject(output)
		if err != nil {
			return true, err
		}
	}

	return true, nil
}

func toTimestamp(d nmea.Date, t nmea.Time) int64 {
	if !d.Valid || !t.Valid {
		return 0
	}
	tm := time.Date(d.YY+2000, time.Month(d.MM), d.DD, t.Hour, t.Minute, t.Second, 0, time.UTC)
	return timeToNano(tm)
}

func timeToNano(t time.Time) int64 {
	return t.UnixNano()
}
